package cn.iocoder.yudao.framework.business.eligibility.service;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.iocoder.yudao.framework.business.basic.dao.repository.LockRedisRepository;
import cn.iocoder.yudao.framework.business.basic.service.impl.AbstractService;
import cn.iocoder.yudao.framework.business.eligibility.pojo.po.EligibilityOrderEntity;
import cn.iocoder.yudao.framework.business.eligibility.pojo.po.EligibilityUserEntity;
import cn.iocoder.yudao.framework.business.eligibility.pojo.vo.EligibilityUserVO;
import cn.iocoder.yudao.framework.common.exception.Assertions;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDateTime;

/**
 * 用户身份资格 Service 实现类
 *
 * @author 山野羡民
 */
@Slf4j
//@org.springframework.stereotype.Service
public abstract class AppEligibilityBaseService<DO extends EligibilityUserEntity, ODO extends EligibilityOrderEntity, VO extends EligibilityUserVO> extends AbstractService<DO, VO> implements AppEligibilityService<DO, ODO> {
    private static final long TIMEOUT_MILLIS = 10 * DateUtils.SECOND_MILLIS;
    private static final String LOCK_KEY = "xianmin:member:eligibility:lock:%d";
    @Resource
    private LockRedisRepository lockRedisRepository;

    @Override
    public DO getOrCreate(Long userId) {
        Assertions.notNull(userId, "未获取到 userId");
        return lockRedisRepository.lock(String.format(LOCK_KEY, userId), TIMEOUT_MILLIS, () -> {
            DO aDo = getInjectedMapper().selectOne("user_id", userId);
            if (aDo == null) {
                aDo = buildForInsert(userId);
                aDo.setUserId(userId);
                aDo.setCumulativePrice(0);
                aDo.setPurchaseCount(0);
                aDo.setDaysCount(0);
                aDo.setLastDays(0);
                aDo.setEnterTime(null);
                aDo.setExpireTime(LocalDateTime.now());
                getInjectedMapper().insert(aDo);
            }
            return aDo;
        });
    }

    @Override
    public void updateWhenPaid(ODO order) {
        DO aDo = buildForUpdate(order, getOrCreate(order.getUserId()));
        aDo.setCumulativePrice(aDo.getCumulativePrice() + order.getPrice());
        aDo.setPurchaseCount(aDo.getPurchaseCount() + 1);
        aDo.setDaysCount(NumberUtil.nullToZero(aDo.getDaysCount()) + order.getDays());
        aDo.setLastDays(order.getDays());
        if (aDo.getEnterTime() == null) {
            aDo.setEnterTime(LocalDateTime.now());
        }
        if (aDo.getExpireTime() == null) {
            aDo.setExpireTime(LocalDateTime.now().plusDays(order.getDays()));
        } else {
            aDo.setExpireTime(aDo.getExpireTime().plusDays(order.getDays()));
        }
        getInjectedMapper().updateById(aDo);
    }

    @Override
    public boolean isValid(Long userId) {
        try {
            DO aDo = getOrCreate(userId);
            return aDo.isValid();
        } catch (Exception e) {
            log.error("isValid error", e);
            return false;
        }
    }

    @Nonnull
    protected DO buildForInsert(@Nonnull Long userId) {
        return ReflectUtil.newInstance(resolveEntityClass());
    }

    @Nonnull
    protected DO buildForUpdate(@Nonnull ODO order, @Nonnull DO aDo) {
        return aDo;
    }

}